﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Caifu;
using Caifu.Clients;
using System.Diagnostics;

namespace Caifu.Stats
{
	/// <summary>
	/// 每日净值统计
	/// </summary>
	public class NetDailyStat
	{
		public void Run()
		{
			while (true)
			{
				try
				{
					DateTime date;
					// 合理时间内进行统计
					if (TradeDateUtil.NowIsNetValueChangeTime(out date))
					{
						this.Stat(date);
					}
				}
				catch (Exception ex)
				{
					ExceptionManager.Catch(ex);
				}
				// 线程休息
				Thread.Sleep(180 * 1000);
			}
		}

		public void Stat()
		{
			var t = TradeDateUtil.GetNetDailyDate();
			this.Stat(t);
		}

		public void Stat(DateTime t)
		{
			// 所有基金
			var allFunds = FundClient.GetAllFunds();

			// 交易日净值
			var tNetValues = NetValueClient.GetNetValues(t);

			// 交易日前一日净值
			var t_1 = TradeDateUtil.GetPreviousTradeDate(t);
			var t_1NetValues = NetValueClient.GetNetValues(t_1);

			var tNetValueDict = tNetValues.ToDictionary(p => p.FundId, p => p);
			var t_1NetValueDict = t_1NetValues.ToDictionary(p => p.FundId, p => p);

			List<NetValueDaily> netValueDailys = new List<NetValueDaily>();

			foreach (var fund in allFunds)
			{
				// 排除封闭式基金
				if (fund.FundType == (int)FundType.ClosedEnd) continue;
				// 排除货币型基金
				if (fund.FundType == (int)FundType.Currency) continue;
				// 排除QDII
				if (fund.IsQDII) continue;

				NetValueDaily netValueDaily = new NetValueDaily();
				netValueDaily.FundId = fund.Id;
				netValueDaily.FundCode = fund.Code;
				netValueDaily.FundName = fund.Name;
				// 设置基金分类
				if (fund.IsQDII)
				{
					netValueDaily.Category = "qdii";
				}
				else
				{
					netValueDaily.Category = ConstantDefinition.GetInvestmentTypeNameEN(fund.InvestmentType);
				}

				if (tNetValueDict.ContainsKey(fund.Id))
				{
					var nv = tNetValueDict[fund.Id];
					netValueDaily.UnitNetValue = nv.UnitNetValue;
					netValueDaily.AccumulatedNetValue = nv.AccumulatedNetValue;
				}
				else
				{
					netValueDaily.UnitNetValue = null;
					netValueDaily.AccumulatedNetValue = null;
				}

				if (t_1NetValueDict.ContainsKey(fund.Id))
				{
					var nv = t_1NetValueDict[fund.Id];
					netValueDaily.PreviousUnitNetValue = nv.UnitNetValue;
					netValueDaily.PreviousAccumulatedNetValue = nv.AccumulatedNetValue;
				}

				var unitGrowthValue = netValueDaily.UnitNetValue - netValueDaily.PreviousUnitNetValue;
				var accumulatedGrowthValue = netValueDaily.AccumulatedNetValue - netValueDaily.PreviousAccumulatedNetValue;
				// 单位净值的涨跌值与累计净值的涨跌值一致
				//if (netValueDaily.PreviousUnitNetValue != 0 && unitGrowthValue == accumulatedGrowthValue)
				if (netValueDaily.PreviousUnitNetValue.HasValue)
				{
					if (netValueDaily.UnitNetValue.HasValue)
					{
						netValueDaily.GrowthValue = unitGrowthValue;
						netValueDaily.GrowthRate = FundAlgorithm.CalculateGrowthRate(
							netValueDaily.UnitNetValue.Value, netValueDaily.PreviousUnitNetValue.Value, 0);
					}
					else
					{
						netValueDaily.GrowthValue = 0;
						netValueDaily.GrowthRate = 0;
					}
				}
				else
				{
					Trace.WriteLine("Code={0}，前一日净值为0", netValueDaily.FundCode);
				}

				netValueDaily.ReportDate = t;
				netValueDaily.PreviousReportDate = t_1;
				netValueDailys.Add(netValueDaily);
			}

			var netValueDailyDict = netValueDailys.ToDictionary(p => p.FundId, p => p);
			var fdbNetValueDailys = NetValueDailyClient.GetAllNetValueDailys();
			var fdbNetValueDailyDict = fdbNetValueDailys.ToDictionary(p => p.FundId, p => p);

			List<NetValueDaily> insertNetValueDailys = new List<NetValueDaily>();
			List<NetValueDaily> updateNetValueDailys = new List<NetValueDaily>();
			List<Guid> deleteFundIds = new List<Guid>();

			// 分组新增与删除
			foreach (var netValueDaily in netValueDailys)
			{
				NetValueDaily fdbNetValueDaily;
				var exist = fdbNetValueDailyDict.TryGetValue(netValueDaily.FundId, out fdbNetValueDaily);
				if (exist)
				{
					if (!netValueDaily.EqualsValue(fdbNetValueDaily))
					{// 当两者业务值不一致时才需要修改，否者忽略
						// 设置新的业务值
						fdbNetValueDaily.FundId = netValueDaily.FundId;
						fdbNetValueDaily.FundCode = netValueDaily.FundCode;
						fdbNetValueDaily.FundName = netValueDaily.FundName;
						fdbNetValueDaily.Category = netValueDaily.Category;
						fdbNetValueDaily.ReportDate = netValueDaily.ReportDate;
						fdbNetValueDaily.UnitNetValue = netValueDaily.UnitNetValue;
						fdbNetValueDaily.AccumulatedNetValue = netValueDaily.AccumulatedNetValue;
						fdbNetValueDaily.RestoredNetValue = netValueDaily.RestoredNetValue;
						fdbNetValueDaily.GrowthValue = netValueDaily.GrowthValue;
						fdbNetValueDaily.GrowthRate = netValueDaily.GrowthRate;
						fdbNetValueDaily.PreviousReportDate = netValueDaily.PreviousReportDate;
						fdbNetValueDaily.PreviousUnitNetValue = netValueDaily.PreviousUnitNetValue;
						fdbNetValueDaily.PreviousAccumulatedNetValue = netValueDaily.PreviousAccumulatedNetValue;
						fdbNetValueDaily.PreviousRestoredNetValue = netValueDaily.PreviousRestoredNetValue;

						updateNetValueDailys.Add(fdbNetValueDaily);
					}
				}
				else
				{
					insertNetValueDailys.Add(netValueDaily);
				}
			}

			// 分组删除
			foreach (var item in fdbNetValueDailys)
			{
				if (!netValueDailyDict.ContainsKey(item.FundId))
				{
					deleteFundIds.Add(item.FundId);
				}
			}

			NetValueDailyClient.DeleteNetValueDailysByFundId(deleteFundIds);
			NetValueDailyClient.AddNetValueDailys(insertNetValueDailys);
			NetValueDailyClient.UpdateNetValueDailys(updateNetValueDailys);
		}
	}
}
